﻿/*   
    Copyright (C) 2009 Galaktika Corporation ZAO

    This file is a part of Galaktika.BusinessMonitor
 
    Galaktika.BusinessMonitor is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
      
    You should have received a copy of the GNU General Public License
    along with Galaktika.BusinessMonitor.  If not, see <http://www.gnu.org/licenses/>.
  
    If GPL v.3 is not suitable for your products or company,
    Galaktika Corp provides Galaktika.BusinessMonitor under a flexible commercial license
    designed to meet your specific usage and distribution requirements.
    If you have already obtained a commercial license from Galaktika Corp,
    you can use this file under those license terms.
*/

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Windows.Controls.Primitives;
using System.Collections.Generic;
using System.Windows.Browser;
using System.Reflection;
using System.ComponentModel;
using System.Windows.Markup;

namespace Galaktika.BI.Silverlight.Controls
{    

    public static class Extensions
    {
        // Methods

        internal static UIElement GetRootVisual(this UIElement element)
        {
            return Application.Current.RootVisual;
        }
        
        //internal static FrameworkElement GetKeyboardFocusedElement()
        //{
        //    return (FocusManager.GetFocusedElement() as FrameworkElement);
        //}

        internal static bool IsInVisualTree(this FrameworkElement elem)
        {
            FrameworkElement reference = elem;
            while ((reference.Parent is FrameworkElement) || (VisualTreeHelper.GetParent(reference) is FrameworkElement))
            {
                reference = (reference.Parent ?? VisualTreeHelper.GetParent(reference)) as FrameworkElement;
            }
            return (reference == Application.Current.RootVisual);
        }

        private static Point AbsolutePosition(UIElement element, Popup popup)
        {
            UIElement root = element.GetRootVisual();
            if (popup == null)
            {
                try
                {
                    return element.TransformToVisual(root).Transform(new Point());
                }
                catch
                {
                }
                return new Point();
            }
            Func<Func<Rect, double>, Func<Rect, Rect>, Func<Rect, Rect>, Rect> func = delegate(Func<Rect, double> size, Func<Rect, Rect> first, Func<Rect, Rect> second)
            {
                Rect arg = new Rect(0.0, 0.0, root.RenderSize.Width, root.RenderSize.Height);
                while (size(arg) > 0.5)
                {
                    Rect intersectingRect = first(arg);
                    if ((popup.Child != null))
                        //&& popup.Child.HitTest(intersectingRect).Contains<UIElement>(element))
                    {
                        arg = intersectingRect;
                    }
                    else
                    {
                        arg = second(arg);
                    }
                }
                return arg;
            };
            return new Point(Math.Round(func(delegate(Rect r)
            {
                return r.Width;
            }, delegate(Rect r)
            {
                return new Rect(r.X, r.Y, r.Width / 2.0, r.Height);
            }, delegate(Rect r)
            {
                return new Rect(r.X + (r.Width / 2.0), r.Y, r.Width / 2.0, r.Height);
            }).X), Math.Round(func(delegate(Rect r)
            {
                return r.Height;
            }, delegate(Rect r)
            {
                return new Rect(r.X, r.Y, r.Width, r.Height / 2.0);
            }, delegate(Rect r)
            {
                return new Rect(r.X, r.Y + (r.Height / 2.0), r.Width, r.Height / 2.0);
            }).Y));
        }

        internal static Size ActualSize(this FrameworkElement element)
        {
            return new Size(element.ActualWidth, element.ActualHeight);
        }

        //internal static void ApplyStyle(this FrameworkElement element, Style style)
        //{
        //    foreach (Setter setter in style.Setters.Where<SetterBase>(delegate(SetterBase s)
        //    {
        //        return s is Setter;
        //    }))
        //    {
        //        object obj2 = setter.Value;
        //        if (setter.Value is DoubleCollection)
        //        {
        //            DoubleCollection doubles = new DoubleCollection();
        //            foreach (double num in setter.Value as DoubleCollection)
        //            {
        //                doubles.Add(num);
        //            }
        //            obj2 = doubles;
        //        }
        //        element.SetValue(setter.Property, obj2);
        //    }
        //}

        internal static void Bind(FrameworkElement source, DependencyProperty sourceDProperty, FrameworkElement target, string targetPropertyPath)
        {
            Binding binding = new Binding(targetPropertyPath);
            binding.Mode = BindingMode.TwoWay;
            binding.Source = target;
            source.SetBinding(sourceDProperty, binding);
        }

        public static int IndexOf(this ItemsControl itemsControl, object value)
        {
            for (int i = 0; i < itemsControl.Items.Count; i++)
            {
                object obj2 = itemsControl.Items[i];
                if (obj2.Equals(value))
                {
                    return i;
                }
            }
            return -1;
        }

        public static GeneralTransform TransformToVisual(this UIElement element, UIElement visual)
        {
            Func<UIElement, Popup> func = delegate(UIElement el)
            {
                FrameworkElement reference = el as FrameworkElement;
                while ((reference != null) && !(reference is Popup))
                {
                    reference = (reference.Parent ?? VisualTreeHelper.GetParent(reference)) as FrameworkElement;
                }
                return reference as Popup;
            };
            Popup elem = func(element);
            Popup popup2 = func(visual);
            if (((elem == null) || elem.IsInVisualTree()) && ((popup2 == null) || popup2.IsInVisualTree()))
            {
                try
                {
                    return element.TransformToVisual(visual);
                }
                catch
                {
                }
                return new TranslateTransform();
            }
            Point point = AbsolutePosition(element, elem);
            Point point2 = AbsolutePosition(visual, popup2);
            TranslateTransform transform = new TranslateTransform();
            transform.X = point.X - point2.X;
            transform.Y = point.Y - point2.Y;
            return transform;
        }

        //internal static Run Copy(this Run run)
        //{
        //    Run run2 = new Run();
        //    run2.FontFamily = run.FontFamily;
        //    run2.FontSize = run.FontSize;
        //    run2.FontStretch = run.FontStretch;
        //    run2.FontStyle = run.FontStyle;
        //    run2.FontWeight = run.FontWeight;
        //    run2.Foreground = run.Foreground;
        //    run2.Language = run.Language;
        //    run2.Text = run.Text;
        //    run2.TextDecorations = run.TextDecorations;
        //    return run2;
        //}

        internal static FrameworkElement FindChild(this FrameworkElement root, Predicate<FrameworkElement> pred)
        {
            Queue<DependencyObject> queue = new Queue<DependencyObject>();
            queue.Enqueue(root);
            while (queue.Count > 0)
            {
                DependencyObject reference = queue.Dequeue();
                if ((reference is FrameworkElement) && pred(reference as FrameworkElement))
                {
                    return (reference as FrameworkElement);
                }
                if (reference != null)
                {
                    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(reference); i++)
                    {
                        queue.Enqueue(VisualTreeHelper.GetChild(reference, i));
                    }
                }
            }
            return null;
        }

        public static Uri GetAbsoluteUri(string uriString)
        {
            if (!uriString.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
            {
                if (uriString.StartsWith("/"))
                {
                    uriString = uriString.Substring(1);
                }
                string absoluteUri = HtmlPage.Document.DocumentUri.AbsoluteUri;
                int num = absoluteUri.LastIndexOf('/');
                uriString = absoluteUri.Substring(0, num + 1) + uriString;
            }
            return new Uri(uriString, UriKind.Absolute);
        }

        internal static Rect GetAccumulatedClip(this FrameworkElement element)
        {
            Point location = new Point();
            try
            {
                location = element.TransformToVisual(element.GetRootVisual()).Transform(new Point(0.0, 0.0));
            }
            catch (ArgumentException)
            {
                return new Rect();
            }
            return element.GetAccumulatedClip(location);
        }

        internal static Rect GetAccumulatedClip(this FrameworkElement element, Point location)
        {
            Rect accumClip = new Rect(0.0, 0.0, DomUtil.SilverlightSize.Width, DomUtil.SilverlightSize.Height);
            Action<Rect, Point> action = delegate(Rect clip, Point local)
            {
                clip.X += local.X;
                clip.Y += local.Y;
                double num = Math.Min(accumClip.Right, clip.Right);
                double num2 = Math.Min(accumClip.Bottom, clip.Bottom);
                accumClip.X = Math.Max(accumClip.X, clip.X);
                accumClip.Y = Math.Max(accumClip.Y, clip.Y);
                accumClip.Width = Math.Max((double)(num - accumClip.X), (double)0.0);
                accumClip.Height = Math.Max((double)(num2 - accumClip.Y), (double)0.0);
            };
            foreach (FrameworkElement element2 in element.GetAllParents())
            {
                Point point2 = new Point();
                Point point = element2.TransformToVisual(element2.GetRootVisual()).Transform(point2);
                if (element2.Clip != null)
                {
                    action(element2.Clip.Bounds, point);
                }
                Geometry layoutClip = LayoutInformation.GetLayoutClip(element2);
                if (layoutClip != null)
                {
                    action(layoutClip.Bounds, point);
                }
                action(new Rect(0.0, 0.0, element2.RenderSize.Width, element2.RenderSize.Height), point);
            }
            return new Rect(Math.Max(0.0, Math.Min(element.ActualWidth, accumClip.X - location.X)), Math.Max(0.0, Math.Min(element.ActualHeight, accumClip.Y - location.Y)), Math.Max(0.0, Math.Min(element.ActualWidth, (accumClip.Width + accumClip.X) - location.X)), Math.Max(0.0, Math.Min(element.ActualHeight, (accumClip.Height + accumClip.Y) - location.Y)));
        }

        internal static IList<FrameworkElement> GetAllParents(this FrameworkElement elem)
        {
            List<FrameworkElement> list = new List<FrameworkElement>();
            if (elem != null)
            {
                FrameworkElement reference = elem;
                while (VisualTreeHelper.GetParent(reference) is FrameworkElement)
                {
                    reference = VisualTreeHelper.GetParent(reference) as FrameworkElement;
                    list.Add(reference);
                }
            }
            return list;
        }

        public static IList<T> GetEnumValues<T>(this Type enumType)
        {
            if (enumType == null)
            {
                throw new ArgumentNullException("enumType");
            }
            if (!enumType.IsEnum)
            {
                throw new InvalidOperationException(string.Format("{0} should be a an EnumType", enumType.Name));
            }
            List<T> list = new List<T>();
            foreach (FieldInfo info in enumType.GetFields())
            {
                if (!info.IsSpecialName)
                {
                    T item = (T)info.GetValue(enumType);
                    if (!list.Contains(item))
                    {
                        list.Add(item);
                    }
                }
            }
            return list;
        }

        public static Type GetNonNullableType(this Type type)
        {
            if (type.IsNullableType())
            {
                return type.GetGenericArguments()[0];
            }
            return type;
        }

        internal static FrameworkElement GetRoot(this FrameworkElement elem)
        {
            FrameworkElement parent = elem;
            while (parent.Parent is FrameworkElement)
            {
                parent = (FrameworkElement)parent.Parent;
            }
            return parent;
        }

        internal static IEnumerable<UIElement> HitTest(this UIElement element, Point intersectingPoint)
        {
            try
            {
                return VisualTreeHelper.FindElementsInHostCoordinates(intersectingPoint, element);
            }
            catch (Exception)
            {
                return new List<UIElement>();
            }
        }

        internal static IEnumerable<UIElement> HitTest(this UIElement element, Rect intersectingRect)
        {
            try
            {
                return VisualTreeHelper.FindElementsInHostCoordinates(intersectingRect, element);
            }
            catch (Exception)
            {
                return new List<UIElement>();
            }
        }

        internal static bool IsInDesignMode(this FrameworkElement element)
        {
            if (!DesignerProperties.GetIsInDesignMode(element))
            {
                return !HtmlPage.IsEnabled;
            }
            return true;
        }

        public static bool IsNullableType(this Type type)
        {
            return (((type != null) && type.IsGenericType) && (type.GetGenericTypeDefinition() == typeof(Nullable<>)));
        }

        public static bool IsNumeric(this Type type)
        {
            if (((((type != typeof(double)) && (type != typeof(float))) && ((type != typeof(int)) && (type != typeof(uint)))) && (((type != typeof(long)) && (type != typeof(ulong))) && ((type != typeof(short)) && (type != typeof(ushort))))) && ((type != typeof(sbyte)) && (type != typeof(byte))))
            {
                return (type == typeof(decimal));
            }
            return true;
        }

        public static bool IsNumericIntegral(this Type type)
        {
            if ((((type != typeof(int)) && (type != typeof(uint))) && ((type != typeof(long)) && (type != typeof(ulong)))) && (((type != typeof(short)) && (type != typeof(ushort))) && (type != typeof(sbyte))))
            {
                return (type == typeof(byte));
            }
            return true;
        }

        public static bool IsNumericIntegralSigned(this Type type)
        {
            if (((type != typeof(int)) && (type != typeof(long))) && (type != typeof(short)))
            {
                return (type == typeof(sbyte));
            }
            return true;
        }

        public static bool IsNumericIntegralUnsigned(this Type type)
        {
            if (((type != typeof(uint)) && (type != typeof(ulong))) && (type != typeof(ushort)))
            {
                return (type == typeof(byte));
            }
            return true;
        }

        public static bool IsNumericNonIntegral(this Type type)
        {
            if ((type != typeof(double)) && (type != typeof(float)))
            {
                return (type == typeof(decimal));
            }
            return true;
        }

        internal static bool IsVisible(this ScrollViewer sv, Rect r)
        {
            return ((((sv.HorizontalOffset <= (r.Left + sv.Padding.Left)) && (sv.HorizontalOffset >= ((r.Right - sv.ViewportWidth) + sv.Padding.Left))) && (sv.VerticalOffset <= (r.Top + sv.Padding.Top))) && (sv.VerticalOffset >= ((r.Bottom - sv.ViewportHeight) + sv.Padding.Top)));
        }

        //public static void MakeRelative(this Popup popup, FrameworkElement relativeElement, Func<List<AnchorMatching>> getLocations)
        //{
        //    new C1RelativePopup(relativeElement, getLocations, popup);
        //}

        //public static void MakeRelative(this Popup popup, FrameworkElement relativeElement, Func<List<AnchorMatching>> getLocations, Func<Point> getPosition, Func<Point> getReferencePosition)
        //{
        //    new C1RelativePopup(relativeElement, getLocations, getPosition, getReferencePosition, popup);
        //}

        public static T New<T>(this Type type)
        {
            ConstructorInfo constructor = type.GetConstructor(new Type[0]);
            if (constructor == null)
            {
                throw new InvalidOperationException(string.Format("Cannot find a default constructor for type {0}", type.FullName));
            }
            return (T)constructor.Invoke(new object[0]);
        }

        public static T New<T>(this Type type, Action<T> initializers)
        {
            T local = type.New<T>();
            if (initializers != null)
            {
                initializers(local);
            }
            return local;
        }

        internal static void OnRootVisualSetted(Action a)
        {
            Action tryRoot = null;
            tryRoot = delegate
            {
                if (Application.Current.RootVisual != null)
                {
                    a();
                }
                else
                {
                    new Grid().Dispatcher.BeginInvoke(tryRoot);
                }
            };
            tryRoot();
        }

        internal static Orientation Opposite(this Orientation value)
        {
            if (value == Orientation.Horizontal)
            {
                return Orientation.Vertical;
            }
            return Orientation.Horizontal;
        }

        internal static void RemoveFromParent(this FrameworkElement elem)
        {
            DependencyObject parent = VisualTreeHelper.GetParent(elem);
            if ((elem != null) && (parent != null))
            {
                Panel panel = parent as Panel;
                ContentControl control = parent as ContentControl;
                ContentPresenter presenter = parent as ContentPresenter;
                ItemsControl control2 = parent as ItemsControl;
                Border border = parent as Border;
                Popup popup = parent as Popup;
                if (panel != null)
                {
                    panel.Children.Remove(elem);
                }
                else if (control != null)
                {
                    control.Content = null;
                }
                else if (presenter != null)
                {
                    presenter.Content = null;
                }
                else if (control2 != null)
                {
                    control2.Items.Remove(elem);
                }
                else if (border != null)
                {
                    border.Child = new Border();
                }
                else
                {
                    if (popup == null)
                    {
                        throw new ArgumentException(string.Format("Cannot remove an element from a {0}", elem.Parent.GetType().Name));
                    }
                    popup.Child = null;
                }
            }
        }

        internal static void ScrollIntoView(this ScrollViewer sv, FrameworkElement elem)
        {
            Point point = elem.TransformToVisual(sv).Transform(new Point(sv.HorizontalOffset, sv.VerticalOffset));
            Rect r = new Rect(point, new Point(point.X + elem.ActualWidth, point.Y + elem.ActualHeight));
            sv.ScrollIntoView(r);
        }

        internal static void ScrollIntoView(this ScrollViewer sv, Rect r)
        {
            if (sv.HorizontalOffset > r.Left)
            {
                sv.ScrollToHorizontalOffset(r.Left);
            }
            else if (sv.HorizontalOffset < (r.Right - sv.ViewportWidth))
            {
                sv.ScrollToHorizontalOffset(r.Right - sv.ViewportWidth);
            }
            if (sv.VerticalOffset > r.Top)
            {
                sv.ScrollToVerticalOffset(r.Top);
            }
            else if (sv.VerticalOffset < (r.Bottom - sv.ViewportHeight))
            {
                sv.ScrollToVerticalOffset(r.Bottom - sv.ViewportHeight);
            }
        }

        internal static bool ToBool(this Visibility v)
        {
            if (v != Visibility.Visible)
            {
                return false;
            }
            return true;
        }

        internal static Visibility ToVisibility(this bool b)
        {
            if (!b)
            {
                return Visibility.Collapsed;
            }
            return Visibility.Visible;
        }

        //internal static void WriteFocusedElement()
        //{
        //    FrameworkElement keyboardFocusedElement = PlatformIndependent.GetKeyboardFocusedElement();
        //    string str = (string)keyboardFocusedElement.GetValue(FrameworkElement.NameProperty);
        //    string str2 = string.IsNullOrEmpty(str) ? "no-name" : str;
        //    if (keyboardFocusedElement != null)
        //    {
        //        string.Format("{0} ({1})", str2, keyboardFocusedElement.GetType().Name);
        //    }
        //}
    }

 

}
